package model

import (
	"fmt"
	"html"
	"my-go-project/utils/token"
	"strings"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type User struct {
	UserID       int     `gorm:"primaryKey; autoIncrement"`
	Email        string  `gorm:"not null; unique"`
	UName        string  `gorm:"not null; default: 'ID'"`
	Password     string  `gorm:"not null"`
	Contact      string  `grom:"null"`
	ContactType  string  `grom:"not null; default: 'wx'"`
	ProfilePhoto string  `gorm:"not null; default: 'PhotoSrc'"`
	Credit       float64 `gorm:"not null; default: 0"`
	FansNum      int     `gorm:"not null; default: 0"`
	IdolNum      int     `gorm:"not null; default: 0"`
}

type UserMini struct {
	UserID       int    `json:"UserID"`
	ProfilePhoto string `json:"ProfilePhoto"`
	UName        string `json:"UName"`
}

type UserWithContact struct {
	UserID       int    `json:"UserID"`
	ProfilePhoto string `json:"ProfilePhoto"`
	UName        string `json:"UName"`
	Contact      string `json:"Contact"`
	ContactType  string `json:"ContactType"`
}

func (u *User) SaveUser() (*User, error) {
	err := DB.Create(&u).Error
	if err != nil {
		return &User{}, err
	}
	return u, nil
}

func (u *User) UpdateUser() (*User, error) {
	err := DB.Model(&u).Updates(u).Error
	if err != nil {
		return &User{}, err
	}
	return u, nil
}

func (u *User) BeforeSave(tx *gorm.DB) error {
	if u.Password != "" {
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
		if err != nil {
			return err
		}
		u.Password = string(hashedPassword)

	}
	u.UName = html.EscapeString(strings.TrimSpace(u.UName))
	return nil
}

/*
func (u *User) BeforeUpdate(tx *gorm.DB) error {

	print("userPassword: ", u.Password, "\n")
	if u.Password != "" {
		print("password update!")
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
		if err != nil {
			return err
		}
		u.Password = string(hashedPassword)
		u.UName = html.EscapeString(strings.TrimSpace(u.UName))
	}
	return nil

}
*/
func GetIDByEmail(email string) (int, error) {
	var ID int
	err := DB.Model(&User{}).Where("email = ?", email).Select("UserID").Limit(1).Take(&ID).Error
	if err != nil {
		return 0, err
	}
	return ID, nil
}

func GetLastID() (int, error) {
	var lastID int
	err := DB.Model(&User{}).Select("UserID").Order("UserID desc").Limit(1).Take(&lastID).Error
	if err != nil {
		return 0, err
	}
	return lastID, nil
}

func GetUserByID(id int) (*User, error) {
	var err error
	u := User{}

	err = DB.Model(User{}).Where("UserID = ?", id).Take(&u).Error
	if err != nil {
		return &u, err
	}
	return &u, nil
}

func GetUserMiniByID(id int) (UserMini, error) {
	var err error
	u := UserMini{}

	err = DB.Model(User{}).Where("UserID = ?", id).Take(&u).Error
	if err != nil {
		return u, err
	}
	return u, nil
}

func GetUserWithContactByID(id int) (UserWithContact, error) {
	var err error
	u := UserWithContact{}

	err = DB.Model(User{}).Where("UserID = ?", id).Take(&u).Error
	if err != nil {
		return u, err
	}
	return u, nil
}

func VerifyPassword(password, hashedPassword string) error {
	fmt.Println(password, hashedPassword)
	return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}

func LoginCheck(email, password string) (string, error) {
	var err error
	u := User{}

	err = DB.Model(User{}).Where("Email= ?", email).Take(&u).Error
	if err != nil {
		return "", err
	}
	err = VerifyPassword(password, u.Password)
	if err != nil && err == bcrypt.ErrMismatchedHashAndPassword {
		return "", err
	}

	token, err := token.GenerateToken(uint(u.UserID))
	token = "Bearer " + token
	if err != nil {
		return "", err
	}
	return token, nil
}

type UserMessage struct {
	UserID       int64  `json:"UserID"`
	ProfilePhoto string `json:"ProfilePhoto"`
	UName        string `json:"UName"`
}

func GetUserMessage(id int) (UserMessage, error) {
	userMessage := UserMessage{}
	if err := DB.Model(&User{}).Where("UserID= ?", id).Take(&userMessage).Error; err != nil {
		return userMessage, err
	}
	return userMessage, nil
}


func SearchUserMessage(search string) ([]UserMessage, error) {
	userMessage := []UserMessage{}
	searchMessage := "%" + search + "%"
	err := DB.Model(&User{}).Where("UName LIKE ?", searchMessage).Find(&userMessage).Error
	if err != nil {
		return userMessage, err
	}
	return userMessage, nil
}

func UpdateContact(id int, contact string, contactType string) error {
	err := DB.Model(&User{}).Where("UserID = ?", id).Updates(User{Contact: contact, ContactType: contactType}).Error
	return err
}
